package edu.whu.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import edu.whu.demo.dao.EntryDao;
import edu.whu.demo.domain.ActivityMember;
import edu.whu.demo.dao.ActivityMemberDao;
import edu.whu.demo.domain.ActivityMemberDTO;
import edu.whu.demo.exception.ActivityMemberException;
import edu.whu.demo.service.IActivityMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2022-11-24
 */
@Service
public class ActivityMemberServiceImpl extends ServiceImpl<ActivityMemberDao, ActivityMember> implements IActivityMemberService {

    @Autowired
    EntryDao entryDao;

    @Override
    public IPage<ActivityMember> getSigns(Long activityIdForSigns,
                                          Integer stage,
                                          Integer count,
                                          Integer pageNum,
                                          Integer pageSize)
    {
        Page<ActivityMember> page = new Page<>(pageNum, pageSize);
        QueryWrapper<ActivityMember> qw = new QueryWrapper<>();
        qw.eq("activity_id", activityIdForSigns);
        if (stage != null)
        {
            qw.eq("stage", stage);
        }
        if (count != null)
        {
            qw.eq("count", count);
        }
        return this.baseMapper.getSigns(page,qw);
    }

    @Override
    public ActivityMember getSign(Long id)
    {
        return this.baseMapper.selectById(id);
    }

    @Override
    public IPage<ActivityMemberDTO> getMemberState(Map<String, Object> condition,
                                                   Integer pageNum,
                                                   Integer pageSize)
    {
        Page<ActivityMemberDTO> page = new Page<>(pageNum, pageSize);
        QueryWrapper<ActivityMemberDTO> qw = new QueryWrapper<>();
        qw.eq(condition.containsKey("sign"), "m.sign", condition.get("sign"));
        qw.eq(condition.containsKey("stage"), "m.stage", condition.get("stage"));
        qw.eq(condition.containsKey("count"), "m.count", condition.get("count"));
        qw.eq(condition.containsKey("activity_id"), "m.activity_id", condition.get("activity_id"));
        qw.eq(condition.containsKey("uid"), "m.uid", condition.get("uid"));
        qw.like(condition.containsKey("name"), "u.name", condition.get("name"));
        return this.baseMapper.getMemberState(page,qw);
    }

    /**
     * 判断是否与本活动已有签到时间重叠
     * @param activityMember
     * @return
     */
    private boolean isOverlap(ActivityMember activityMember)
    {
        QueryWrapper<ActivityMember> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(
                a->a.and(b->b.ge("begin_time",activityMember.getBeginTime()).le("begin_time",activityMember.getEndTime()))
                        .or(c->c.ge("end_time",activityMember.getBeginTime()).le("end_time",activityMember.getEndTime()))
                        .or(d->d.le("begin_time",activityMember.getBeginTime()).ge("end_time",activityMember.getEndTime()))
                        .or(e->e.ge("begin_time",activityMember.getBeginTime()).le("end_time",activityMember.getEndTime()))
        );
        queryWrapper.eq("activity_id",activityMember.getActivityId());
        //同一个活动同阶段同次数的签到可以不算时间重叠
        queryWrapper.and(
                a->a.ne("count",activityMember.getCount())
                        .or()
                        .ne("stage",activityMember.getStage())
        );
        return !this.baseMapper.selectList(queryWrapper).isEmpty();
    }

    /**
     * 找到本活动当前阶段已有的最大签到次数
     * @param activityMember
     * @return
     */
    private Integer currentLargestCount(ActivityMember activityMember)
    {
        QueryWrapper<ActivityMember> qw = new QueryWrapper<>();
        qw.eq("stage",activityMember.getStage())
                .eq("activity_id",activityMember.getActivityId())
                .select("max(count)");
        return (Integer) this.baseMapper.selectObjs(qw).get(0);
    }

    private void decreaseLargerCount(ActivityMember activityMember) throws ActivityMemberException
    {

        QueryWrapper<ActivityMember> qw = new QueryWrapper<>();
        //查询本活动本阶段签到次数更大的签到
        qw.gt("count",activityMember.getCount())
                .eq("stage",activityMember.getStage())
                .eq("activity_id",activityMember.getActivityId());
        List<ActivityMember> list = this.baseMapper.selectList(qw);
        try {
            for (ActivityMember item: list)
            {
                //将这些签到次数更大的签到的签到次数减一
                item.setCount(item.getCount()-1);
                this.baseMapper.updateById(item);
            }
        }
        catch (Exception e)
        {
            throw new ActivityMemberException("更新签到失败："+e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ActivityMember addSign(ActivityMember activityMember) throws ActivityMemberException
    {
        Integer currentLargestCount = currentLargestCount(activityMember);
        Integer count = currentLargestCount == null ? 1:currentLargestCount+1;
        // 在currentLargestCount基础上+1，即保证签到次数必须是递增的
        activityMember.setCount(count);
        if (isOverlap(activityMember))
        {
            throw new ActivityMemberException("与已有签到时间重叠，请重新设置！");
        }
        activityMember.setProof("");
        //sign有 待提交、待阅、签到成功、签到失败 四种状态
        activityMember.setSign("未提交");
        List<Long> uidList = entryDao.getUids(activityMember.getActivityId());
        try
        {
            for (Long uid: uidList)
            {
                activityMember.setUid(uid);
                this.baseMapper.insert(activityMember);
            }
        }
        catch (Exception e)
        {
            throw new ActivityMemberException("发布签到失败："+e.getMessage());
        }
        return activityMember;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateMultipleSign(ActivityMember oldActivityMember, ActivityMember newActivityMember) throws ActivityMemberException
    {
        if (isOverlap(oldActivityMember))
        {
            throw new ActivityMemberException("与已有签到时间重叠，请重新设置！");
        }
        //获取需要更新的签到
        QueryWrapper<ActivityMember> wrapper = new QueryWrapper<>();
        wrapper.eq("count",oldActivityMember.getCount())
                .eq("stage",oldActivityMember.getStage())
                .eq("activity_id",oldActivityMember.getActivityId());
        List<ActivityMember> updateList = this.baseMapper.selectList(wrapper);

        Integer count = oldActivityMember.getCount();
        //只有阶段变化才可能导致签到次数变化
        if (!oldActivityMember.getStage().equals(newActivityMember.getStage())) {
            Integer currentLargestCount = currentLargestCount(newActivityMember);
            count = currentLargestCount == null ? 1:currentLargestCount+1;
            newActivityMember.setCount(count);
        }

        try
        {
            for (ActivityMember activityMember: updateList)
            {
                newActivityMember.setId(activityMember.getId());
                newActivityMember.setUid(activityMember.getUid());
                newActivityMember.setSign(activityMember.getSign());
                newActivityMember.setProof(activityMember.getProof());
                //newCount的计算也许在前端实现也可,前端需上传正确的newCount和newStage
                this.baseMapper.updateById(newActivityMember);
            }
            //只有阶段变化才可能导致签到次数变化
            if (!oldActivityMember.getStage().equals(newActivityMember.getStage())) {
                decreaseLargerCount(oldActivityMember);
            }
        }
        catch (Exception e)
        {
            throw new ActivityMemberException("更新签到失败："+e.getMessage());
        }
        return count;
    }

    /**
     * 该方法只用来修改sign，因此不检查时间重叠等问题
     * @param activityMember
     * @throws ActivityMemberException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSingleSign(ActivityMember activityMember) throws ActivityMemberException
    {
        try
        {
            this.baseMapper.updateById(activityMember);
        }
        catch (Exception e)
        {
            throw new ActivityMemberException("更新签到失败："+e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSign(ActivityMember activityMember) throws ActivityMemberException
    {
        QueryWrapper<ActivityMember> wrapper = new QueryWrapper<>();
        if (activityMember.getStage() != null)
        {
            wrapper.eq("stage",activityMember.getStage());
        }
        if (activityMember.getCount() != null)
        {
            wrapper.eq("count",activityMember.getCount());
        }
        if (activityMember.getActivityId() != null)
        {
            wrapper.eq("activity_id",activityMember.getActivityId());
        }
        if (activityMember.getUid() != null)
        {
            wrapper.eq("uid",activityMember.getUid());
        }
        try
        {
            this.baseMapper.delete(wrapper);
        }
        catch (Exception e)
        {
            throw new ActivityMemberException("更新签到失败："+e.getMessage());
        }
        if (activityMember.getStage() != null && activityMember.getCount() != null)
        {
            //将该活动本阶段count更大的签到次数都减一
            decreaseLargerCount(activityMember);
        }
    }

    public ActivityMember onlyLegalSign(Long activityId, Long uid) throws ActivityMemberException
    {
        QueryWrapper<ActivityMember> qw = new QueryWrapper<>();
        qw.eq("activity_id", activityId)
                .eq("uid", uid)
                .le("begin_time", LocalDateTime.now())
                .ge("end_time", LocalDateTime.now());
        List<ActivityMember> res = this.baseMapper.selectList(qw);
        if (res.size() > 1)
        {
            throw new ActivityMemberException("同时开启的签到个数大于一！");
        }
        if (res.isEmpty())
        {
            throw new ActivityMemberException("现在没有正在开启的签到！");
        }
        return res.get(0);
    }

    public List<ActivityMember> getByActivityId(long activityId){
        return this.baseMapper.getByActivityId(activityId);
    }

}
